/**
 * 
 * @returns RopeModel
 */
function RopeModel() {
	var speed = Math.max(Math.random(), 0.2);
	this.top = {
		position : -1,
		fireTime : -1,
		initialSpeed : speed,
		endSpeed : 1 - speed
	};
	this.bottom = {
		position : -1,
		fireTime : -1,
		initialSpeed : 1 - speed,
		endSpeed : speed
	};
	this.timeLength = 30;
}

RopeModel.prototype.getState = function() {
	var result = {};
	result.top = this.top.position;
	result.bottom = this.bottom.position;
	result.burned = this.isFullBurned();

	return result;
};

RopeModel.prototype.setFire = function(time, extremity) {
	this[extremity].fireTime = time;
	this[extremity].position = 0;

};

RopeModel.prototype.updateTime = function(time) {
	this.updateExtremityState(this.top, time);
	this.updateExtremityState(this.bottom, time);
};

RopeModel.prototype.updateExtremityState = function(extremity, time) {
	if (extremity.fireTime >= 0) {
		var dt1 = Math.min(time - extremity.fireTime, this.timeLength / 2);
		var dt2 = Math.max(time - extremity.fireTime - this.timeLength / 2, 0);

		extremity.position = 2 * (extremity.initialSpeed * dt1 + extremity.endSpeed * dt2) / this.timeLength;
		extremity.position = Math.min(1, extremity.position);
	}
};

RopeModel.prototype.isFullBurned = function() {
	var topPosition = Math.max(this.top.position, 0);
	var bottomPosition = Math.max(this.bottom.position, 0);

	return (topPosition + bottomPosition >= 1);
};

/**
 * 
 * @returns RopeController
 */
function RopeController(view) {
	this.view = view;
	this.tolerance = 2;
	this.init();
}

RopeController.prototype.init = function() {
	this.time = 0;
	this.initRopes();
};

RopeController.prototype.initRopes = function() {
	this.ropes = [];
	this.ropes[0] = new RopeModel();
	this.ropes[1] = new RopeModel();
};

RopeController.prototype.startup = function() {
	this.view.init(this);
	this.updateView();
};

RopeController.prototype.reset = function() {
	this.init();
	this.updateView();
};

RopeController.prototype.updateView = function() {
	this.view.update(this.getRopesState());
};

RopeController.prototype.getRopesState = function() {
	var state = [];
	for ( var i = 0; i < this.ropes.length; i++) {
		state.push(this.ropes[i].getState());
	}

	return state;
};

RopeController.prototype.onSetFire = function(ropeIndex, extremity) {
	this.ropes[ropeIndex].setFire(this.time, extremity);
	this.updateView();
};

RopeController.prototype.updateTime = function(now) {
	this.time = Math.min(now, 45 + this.tolerance);
	this.updateRopes(this.time);
	this.updateView();

	var state = this.getState();
	if (state.solved) {
		new AEnigmatesStorage("ropes").solved();
		this.view.onSolved();
	} else if (!state.inProgress) {
		this.view.onStale(state.overTime);
	}
};

RopeController.prototype.getState = function() {
	var allBurned = true;
	for ( var i = 0; i < this.ropes.length; i++) {
		if (!this.ropes[i].isFullBurned()) {
			allBurned = false;
			break;
		}
	}

	var state = {
		inProgress : null,
		solved : null,
		overTime : null
	};
	var tolerance = this.tolerance;
	if (allBurned) {
		state.solved = (Math.abs(this.time - 45) <= tolerance);
		state.inProgress = false;
	} else {
		state.solved = false;
		state.inProgress = (this.time < 45 + tolerance);
	}

	state.overTime = (this.time >= 45 + tolerance);

	return state;
};

RopeController.prototype.updateRopes = function(now) {
	for ( var i = 0; i < this.ropes.length; i++) {
		this.ropes[i].updateTime(now);
	}
};
